package edu.ncsu.csc.ip.common;

public class TimeEstimator {

	public static double finel_transfer_delay(int n, double rtt,
			double timeout, double p, int filesize, int mss) {
		return (filesize / mss) * expected_delay(n, rtt, timeout, p);
	}

	/*
	 * 
	 * p is probability of success n is receiver count
	 */
	public static double expected_delay(int n, double rtt, double timeout,
			double p) {

		if (n == 0)
			return 0.0d;
		if (n == 1)
			return rtt + (timeout * (1 - p) / p);

		double first_delay = rtt * Math.pow(p, n);

		double last_timout_delay = timeout * Math.pow(1 - p, n);

		double expected_delay = 0;

		for (int i = 1; i < n; i++) {
			expected_delay += (binomial(n, i) * Math.pow(1 - p, i)
					* Math.pow(p, n - i) * (timeout + expected_delay(i, rtt,
					timeout, p)));
		}

		return (expected_delay + first_delay + last_timout_delay)
				/ (1 - Math.pow(1 - p, n));
	}

	/*
	 * 
	 * p is probability of success n is receiver count
	 */
	public static double expected_rount(int n, double p) {

		if (n == 0)
			return 0.0d;
		if (n == 1)
			return (1 / p);

		double last_delay = Math.pow(1 - p, n);

		double expected_delay = 0;

		for (int i = 0; i < n; i++) {
			expected_delay += (binomial(n, i) * Math.pow(1 - p, i)
					* Math.pow(p, n - i) * (1 + expected_rount(i, p)));
		}

		return (expected_delay + last_delay) / (1 - Math.pow(1 - p, n));
	}

	static long binomial(final int N, final int K) {
		long ret = 1;
		for (int k = 0; k < K; k++) {
			ret = ret * (N - k) / (k + 1);
		}
		if (ret == 0)
			throw new RuntimeException("c(" + N + "," + K + ") = " + ret);
		// System.out.println("c(" + N + "," + K + ") = " + ret);
		return ret;
	}

	public static void main(String[] args) {
		// System.out.println(expected_rount(5, 0.95));
		// System.out.println(expected_delay(5,0.02d,1d, 0.95d));
		// Task 1
		double rtt = 0.031;
		double timeout = 0.1;
		int file_size = 9822252;
		int mss = 500;
		double p = 0.95;
		int receivers = 3;

		try {
			receivers = Integer.valueOf(args[0]);
			p = (1-Double.valueOf(args[1]));
			rtt = Double.valueOf(args[2]);
			timeout = Double.valueOf(args[3]);
			file_size = Integer.valueOf(args[4]);
			mss = Integer.valueOf(args[5]);

		} catch (Exception e) {
			System.out
					.println("USAGE:\n TimeEstimator <receivers> <p of loss> <RTT> <Timeout> <File Size> <MSS>");
			System.out
			.println("EXAMPLE:\n TimeEstimator 3 0.05 0.03 0.99 10000000 500");
			System.out.println("Proceeding with default values.");
		}

		// Task 1


		System.out
				.println("-----------------------------------------------------------");
		System.out.println("Task 1 ");

		System.out.println("	Receivers = 1-5");
		System.out.println("	P of loss= " + (1 - p));
		System.out.println("	RTT = " + rtt + " seconds");
		System.out.println("	Timeout = " + timeout + " seconds");
		System.out.println("	File Size = " + file_size + " bytes");
		System.out.println("	MSS = " + mss + " bytes");

		System.out.println("");

		for (int i = 1; i < 6; i++) {
			System.out.println(i + " Recevers | Time:"
					+ finel_transfer_delay(i, rtt, timeout, p, file_size, mss)
					+ " seconds.");
		}

		System.out
				.println("-----------------------------------------------------------");
		System.out.println("Task 2 ");

		System.out.println("	Receivers = " + receivers);
		System.out.println("	P of loss= " + (1 - p));
		System.out.println("	RTT = " + rtt + " seconds");
		System.out.println("	Timeout = " + timeout + " seconds");
		System.out.println("	File Size = " + file_size + " bytes");
		System.out.println("	MSS = " + "(100-1000)" + " bytes");

		System.out.println("");

		for (int i = 1; i < 11; i++) {
			System.out.println(i
					* 100
					+ " MSS | Time:"
					+ finel_transfer_delay(receivers, rtt, timeout, p,
							file_size, i * 100) + " seconds.");
		}

		System.out
				.println("-----------------------------------------------------------");
		System.out.println("Task 3 ");

		System.out.println("	Receivers = " + receivers);
		System.out.println("	P of loss= " + ".01 - .1 ");
		System.out.println("	RTT = " + rtt + " seconds");
		System.out.println("	Timeout = " + timeout + " seconds");
		System.out.println("	File Size = " + file_size + " bytes");
		System.out.println("	MSS = " + mss + " bytes");

		System.out.println("");

		for (double i = 1; i < 11; i++) {
			System.out.println(( i / 100)
					+ " P | Time:"
					+ finel_transfer_delay(receivers, rtt, timeout,
							(1 - i / 100), file_size, mss) + " seconds.");
		}

		System.out
				.println("-----------------------------------------------------------");
	}
}
